﻿using System.Net;
using CommonTools;
using CommonTools.HttpClient;
using Discord.Param;
using Discord.Response;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ViewModel.Enum;

namespace Discord;

/// <summary>
/// mj接口
/// </summary>
public class DiscordApi
{
    #region 属性

    /// <summary>
    /// 频道ID
    /// </summary>
    private static string CHANNEL_ID { get; } = AppConfigurationServices.Configuration["DiscordSetting:CHANNEL_ID"];

    /// <summary>
    /// API反向代理地址(原值https://discord.com)
    /// </summary>
    private static string API_URL { get; } = AppConfigurationServices.Configuration["DiscordSetting:API_URL"];

    /// <summary>
    /// 服务器ID
    /// </summary>
    private static string GUILD_ID { get; } = AppConfigurationServices.Configuration["DiscordSetting:GUILD_ID"];

    /// <summary>
    /// 用户token
    /// </summary>
    private static string[] USER_TOKEN { get; } = AppConfigurationServices.Configuration["DiscordSetting:USER_TOKEN"].Split(",");

    /// <summary>
    /// 已经使用过的token
    /// </summary>
    private static List<string> Displayed_TOKEN { get; set; } = new();

    /// <summary>
    /// 当前token
    /// </summary>
    private static string CurrentUserToken { get; set; } = "";

    /// <summary>
    /// 基础api地址
    /// </summary>
    private static string BaseUrl => string.IsNullOrWhiteSpace(API_URL) ? "https://discord.com" : API_URL;

    /// <summary>
    /// 提交mj参数接口地址
    /// </summary>
    private static string TRIGGER_URL => $"{BaseUrl}/api/v9/interactions";

    /// <summary>
    /// 上传附件接口地址
    /// </summary>
    private static string UPLOAD_ATTACHMENT_URL { get; } = $"{BaseUrl}/api/v9/channels/{CHANNEL_ID}/attachments";

    /// <summary>
    /// 发送图片接口地址
    /// </summary>
    private static string SEND_MESSAGE_URL { get; } = $"{BaseUrl}/api/v9/channels/{CHANNEL_ID}/messages";

    /// <summary>
    /// 方法类型字典
    /// </summary>
    private static readonly Dictionary<Enum, int> TriggerDictionary = new()
    {
        {TriggerType.Generate,2},
        {TriggerType.Upscale,3},
        {TriggerType.Variation,3},
        {TriggerType.Reset,3},
        {TriggerType.Describe,2},
        {TriggerType.SoloVariation,3},
        {TriggerType.SoloLowVariation,3},
        {TriggerType.SoloHighVariation,3},
        {TriggerType.Expand,3},
        {TriggerType.ZoomOut,3}
    };

    #endregion

    /// <summary>
    /// 基础请求
    /// </summary>
    /// <param name="param"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    private static async ValueTask<bool> Trigger(BasePayload param, int type = 0)
    {
        string data = JsonConvert.SerializeObject(param);
        HttpStatusCode code;

        if (Displayed_TOKEN.Count == USER_TOKEN.Length)
        {
            Displayed_TOKEN.Clear();
        }

        if (string.IsNullOrEmpty(CurrentUserToken))
        {
            CurrentUserToken = USER_TOKEN.FirstOrDefault() ?? string.Empty;
            Displayed_TOKEN.Add(CurrentUserToken);
        }
        else
        {
            string token = USER_TOKEN.FirstOrDefault(d => Displayed_TOKEN.All(x => x != d)) ?? string.Empty;
            CurrentUserToken = token;
            Displayed_TOKEN.Add(CurrentUserToken);
        }
        if (type == 0)
            code = await HttpClientHelper.SendAsyncForm(TRIGGER_URL, HttpMethod.Post, data, CurrentUserToken);
        else
            code = await HttpClientHelper.SendAsync(TRIGGER_URL, HttpMethod.Post, data, CurrentUserToken);
        return code == HttpStatusCode.NoContent;
    }

    /// <summary>
    /// 绘制
    /// </summary>
    /// <param name="prompt">描述</param>
    /// <returns></returns>
    public static async ValueTask<bool> Generate(string prompt)
    {
        var param = new GeneratePayLoad
        {
            Type = TriggerDictionary[TriggerType.Generate],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            Data = new GeneratePayLoadInfo
            {
                OptionList = new List<OptionsInfo>
               {
                   new ()
                   {
                       Value = prompt
                   }
               }
            }
        };

        return await Trigger(param);
    }

    /// <summary>
    /// 放大指定图片
    /// </summary>
    /// <param name="index">图片索引</param>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <returns></returns>
    public static async ValueTask<bool> Upscale(int index, string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.Upscale],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::upsample::{index}::{msgHash}"
            }
        };

        return await Trigger(param, 1);
    }

    /// <summary>
    /// 优化指定图片
    /// </summary>
    /// <param name="index">图片索引</param>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <returns></returns>
    public static async ValueTask<bool> Variation(int index, string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.Variation],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::variation::{index}::{msgHash}"
            }
        };

        return await Trigger(param, 1);
    }

    /// <summary>
    /// 重新绘制
    /// </summary>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <returns></returns>
    public static async ValueTask<bool> Reset(string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.Reset],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::reroll::0::{msgHash}::SOLO"
            }
        };
        return await Trigger(param, 1);
    }

    /// <summary>
    /// 做出变化
    /// </summary>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <returns></returns>
    public static async ValueTask<bool> SoloVariation(string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.SoloVariation],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::variation::1::{msgHash}::SOLO"
            }
        };
        return await Trigger(param, 1);
    }

    /// <summary>
    /// 变化（细微）
    /// </summary>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <returns></returns>
    public static async ValueTask<bool> SoloLowVariation(string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.SoloLowVariation],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::low_variation::1::{msgHash}::SOLO"
            }
        };
        return await Trigger(param, 1);
    }

    /// <summary>
    /// 变化（强）
    /// </summary>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <returns></returns>
    public static async ValueTask<bool> SoloHighVariation(string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.SoloHighVariation],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::high_variation::1::{msgHash}::SOLO"
            }
        };
        return await Trigger(param, 1);
    }

    /// <summary>
    /// ⬅️➡️⬆️⬇️
    /// </summary>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <param name="direction">right/left/up/down</param>
    /// <returns></returns>
    public static async ValueTask<bool> Expand(string msgId, string msgHash, string direction)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.Expand],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::JOB::pan_{direction}::1::{msgHash}::SOLO"
            }
        };
        return await Trigger(param, 1);
    }

    /// <summary>
    /// 缩小2倍/1.5倍
    /// </summary>
    /// <param name="msgId">报文id</param>
    /// <param name="msgHash">报文文件名</param>
    /// <param name="zoomOut">2x: 50; 1.5x: 75</param>
    /// <returns></returns>
    public static async ValueTask<bool> ZoomOut(int zoomOut, string msgId, string msgHash)
    {
        var param = new OperatePayLoad
        {
            Type = TriggerDictionary[TriggerType.ZoomOut],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            MessageId = msgId,
            Data = new OperatePayLoadInfo
            {
                CustomId = $"MJ::Outpaint::{zoomOut}::1::{msgHash}::SOLO"
            }
        };
        return await Trigger(param, 1);
    }

    /// <summary>
    /// 图片会说话
    /// </summary>
    /// <param name="upLoadFileName">图片地址</param>
    /// <returns></returns>
    public static async ValueTask<bool> Describe(string upLoadFileName)
    {
        var param = new DescribePayLoad()
        {
            Type = TriggerDictionary[TriggerType.Describe],
            ChannelId = CHANNEL_ID,
            GuildId = GUILD_ID,
            Data = new DescribePayLoadInfo()
            {
                OptionList = new List<DOptionsInfo>
                {
                    new ()
                },
                Attachments = new List<DAttachmentInfo>
                {
                    new ()
                    {
                        FileName = upLoadFileName.Split("/")[^1],
                        UpLoadedFileName = upLoadFileName
                    }
                }
            }
        };

        return await Trigger(param);
    }

    /// <summary>
    /// 上传文件
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="fileSize">文件大小</param>
    /// <param name="path">本地图片地址</param>
    /// <returns></returns>
    public static async ValueTask<(bool, UploadData ret)> UploadAttachment(string fileName, int fileSize, string path)
    {
        var param = new UploadParam();
        param.FileList.Add(new UploadInfo
        {
            FileName = fileName,
            FileSize = fileSize
        });
        string data = JsonConvert.SerializeObject(param);
        (HttpStatusCode code, JObject ret) = await HttpClientHelper.SendAsyncRes(UPLOAD_ATTACHMENT_URL, HttpMethod.Post, data, CurrentUserToken);
        if (code != HttpStatusCode.OK)
        {
            return (false, new UploadData());
        }

        var uploadResult = ret["data"]?.ToObject<UploadResult>() ?? new UploadResult();
        if (uploadResult.AttachmentList.Count == 0)
        {
            return (false, new UploadData());
        }

        string dUploadUrl = uploadResult.AttachmentList.FirstOrDefault()?.UploadUrl ?? string.Empty;
        var dUploadUrlCode = await HttpClientHelper.SendAsync(dUploadUrl, HttpMethod.Put, path, CurrentUserToken, "image/png");
        if (dUploadUrlCode != HttpStatusCode.OK)
        {
            return (false, new UploadData());
        }

        return (true, uploadResult.AttachmentList.FirstOrDefault() ?? new UploadData());
    }

    /// <summary>
    /// 发送图片
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <returns></returns>
    public static async ValueTask<(bool, string ret)> SendAttachmentMessage(string fileName)
    {
        var param = new SendAttachmentParam();
        param.AttachmentList.Add(new SendUploadInfo
        {
            FileName = fileName.Split("/")[^1],
            UploadedFileName = fileName
        });
        string data = JsonConvert.SerializeObject(param);
        (HttpStatusCode code, JObject ret) = await HttpClientHelper.SendAsyncRes(SEND_MESSAGE_URL, HttpMethod.Post, data, CurrentUserToken);
        if (code != HttpStatusCode.OK)
        {
            return (false, "");
        }

        string url = TryGetJsonValueString(ret, "url");
        if (string.IsNullOrEmpty(url))
        {
            return (false, "");
        }
        return (true, url);
    }

    #region 私有方法

    /// <summary>
    /// 获取json中的值
    /// </summary>
    private static string TryGetJsonValueString(JObject dataJson, string key)
    {

        return dataJson.TryGetValue(key, out JToken value) ? value.ToString() : string.Empty;
    }

    #endregion
}